﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.CustomTool;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using System.CodeDom;
using System.IO;
using System.CodeDom.Compiler;
using NameMapping.CodeDom;

namespace NameMapping.CustomTool
{
    // You have to make sure that the value of this attribute (Guid) 
    // is exactly the same as the value of the field 'CustomToolGuid' 
    // (in the registration region)
    [Guid("BB5B6BBB-7081-44D2-8DDB-4ADCC2ACCC68")]
    [ComVisible(true)]
    public class NameMappingCodeGenTool : BaseCodeGeneratorWithSite
    {
        // This method is being called every time the atached xml is saved.
        protected override byte[] GenerateCode(
            string inputFileName, string inputFileContent)
        {
            try
            {
                // Try to generate the wrapper file.
                return GenerateCodeSafe(inputFileName);
            }
            catch (Exception ex)
            {
                // In case of a faliure - print the exception 
                // as a comment on the code file.
                return GenerateExceptionMessage(ex);
            }
        }
        private byte[] GenerateExceptionMessage(Exception ex)
        {
            CodeCompileUnit code = new CodeCompileUnit();
            CodeNamespace codeNamespace = new CodeNamespace(FileNameSpace);
            code.Namespaces.Add(codeNamespace);

            codeNamespace.Comments.Add(new CodeCommentStatement(ex.ToString()));

            string stringcode = WriteCode(CodeProvider, code);

            return Encoding.ASCII.GetBytes(stringcode);
        }

        private byte[] GenerateCodeSafe(string inputFileName)
        {
            CodeCompileUnit code = Generator.Parse(inputFileName,FileNameSpace);
            string stringcode = WriteCode(CodeProvider, code);

            return Encoding.ASCII.GetBytes(stringcode);
        }

        private static string WriteCode(CodeDomProvider p_provider, CodeCompileUnit code)
        {
            StringWriter stringwriter = new StringWriter();
            p_provider.GenerateCodeFromCompileUnit(code, stringwriter, null);
            string stringcode = stringwriter.ToString();
            stringwriter.Close();

            return stringcode;
        }

        #region Registration

        // You have to make sure that the value of this field (CustomToolGuid) is exactly 
        // the same as the value of the Guid attribure (at the top of the class)
        private static Guid CustomToolGuid =
            new Guid("{BB5B6BBB-7081-44D2-8DDB-4ADCC2ACCC68}");

        private static Guid CSharpCategory =
            new Guid("{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}");

        private static Guid VBCategory =
            new Guid("{164B10B9-B200-11D0-8C61-00A0C91E29D5}");

        private const string CustomToolName = "NameMapping2Objects";

        private const string CustomToolDescription = "Provide IntelliSense for TestComplete NameMapping";

        private const string KeyFormat
            = @"SOFTWARE\Microsoft\VisualStudio\{0}\Generators\{1}\{2}";

        protected static void Register(Version vsVersion, Guid categoryGuid)
        {
            string subKey = String.Format(KeyFormat,
                vsVersion, categoryGuid.ToString("B"), CustomToolName);

            using (RegistryKey key = Registry.LocalMachine.CreateSubKey(subKey))
            {
                key.SetValue("", CustomToolDescription);
                key.SetValue("CLSID", CustomToolGuid.ToString("B"));
                key.SetValue("GeneratesDesignTimeSource", 1);
            }
        }

        protected static void Unregister(Version vsVersion, Guid categoryGuid)
        {
            string subKey = String.Format(KeyFormat,
                vsVersion, categoryGuid.ToString("B"), CustomToolName);

            Registry.LocalMachine.DeleteSubKey(subKey, false);
        }

        [ComRegisterFunction]
        public static void RegisterClass(Type t)
        {
            Register(new Version(9, 0), CSharpCategory);
            Register(new Version(9, 0), VBCategory); 
            Register(new Version(10, 0), CSharpCategory);
            Register(new Version(10, 0), VBCategory);
        }

        [ComUnregisterFunction]
        public static void UnregisterClass(Type t)
        { 
            Unregister(new Version(9, 0), CSharpCategory);
            Unregister(new Version(9, 0), VBCategory);
            Unregister(new Version(10, 0), CSharpCategory);
            Unregister(new Version(10, 0), VBCategory);
        }

        #endregion
    }
}

